#include "Radar.h"
#include<iostream>

using namespace std;
using namespace bfs;

Radar::Radar()
{
	m_bCreate = false;
}

int Radar::scan(string sSourceDir, bool bRecurse, bool bCreate)
{
    size_t nLength = sSourceDir.length();
    if(nLength<1) return 1;

    if(sSourceDir.at(nLength-1) == '/'){
        sSourceDir = sSourceDir.substr(0,nLength -1);
    }

	m_bCreate = bCreate;
	m_xCodebaseRoot = complete(path(sSourceDir, native));
	m_xCodebaseRoot = system_complete(m_xCodebaseRoot);

	if( !exists(m_xCodebaseRoot) )
	{
		cerr<<m_xCodebaseRoot.leaf()<<" does not exist.\n";
		return 2;
	}

	if( !is_directory(m_xCodebaseRoot))
	{
		cerr<<m_xCodebaseRoot.leaf()<<" is not a directory.\n";
		return 3;
	}

	m_xNeptunerRoot = complete(path("_neptuner"),m_xCodebaseRoot);
	m_xNeptunerRoot = system_complete(m_xNeptunerRoot);

	if(m_bCreate)
		create_directory(m_xNeptunerRoot);

	scanDirectory(m_xCodebaseRoot);

	return 0;
}

bool Radar::isFileTypeSupported(string sExtension)
{
	if(sExtension == ".c" )		return true;
	if(sExtension == ".cpp" )	return true;
	if(sExtension == ".h" )		return true;
	if(sExtension == ".hpp")	return true;

	return false;
}

bool Radar::isInExcludeList(std::string sFilename)
{
	if(sFilename[0] == '.')		
		return true;

	for(size_t i=0; i< m_asExclusions.size(); i++){
		//TODO: incorporate regex *.???
		if(sFilename == m_asExclusions[i])
			return true;
	}
	return false;
}


string Radar::getCodebaseLocation(bfs::path xDirEntryPath)
{
	string sSourceDirBase	=  m_xCodebaseRoot.directory_string();
	string sDirEntryPath	=  xDirEntryPath.string();

	sDirEntryPath.erase(0,sSourceDirBase.length()+1);
	//+1 since starting with / also absolute path!
	return sDirEntryPath;
}

int Radar::createShadowDirFor(path xSourceDir)
{
	string sSourceDir = xSourceDir.string();

	if(xSourceDir == m_xNeptunerRoot)
		return 1;
		//Otherwise recursive directories created if TargetDirBase is within SourceDirBase

	sSourceDir = getCodebaseLocation(sSourceDir);
	path xShadowDir = complete(path(sSourceDir), m_xNeptunerRoot);
	xShadowDir = system_complete(xShadowDir);

	if(m_bCreate)
		create_directory(xShadowDir);

	return 0;
}

void Radar::scanDirectory(const path& xPath, int nLevel, bool bRecurse)
{
	directory_iterator pxLooper(xPath); //VSExpress Intellisense has a problem with this
	directory_iterator pxLoopEnd;
	path xDirEntry;
	CodebaseUnit* pxCodebaseUnit = NULL;

	for(; pxLooper != pxLoopEnd; ++pxLooper)
	{
		xDirEntry = *pxLooper;

		try {
		if(isInExcludeList(xDirEntry.filename()))
			continue;

		bool bIsDirectory = is_directory(xDirEntry);
		if(bIsDirectory)
		{
			if( 0!= createShadowDirFor(xDirEntry))
				continue;

			if(bRecurse)
				scanDirectory(xDirEntry, nLevel, bRecurse);
		}
		else
			//For files
		{
			string sFileExtension = extension(xDirEntry);
			if (!isFileTypeSupported(sFileExtension))
				continue;
		}

		pxCodebaseUnit = new CodebaseUnit;
		pxCodebaseUnit->m_sName = xDirEntry.filename();
		pxCodebaseUnit->m_sLocation = getCodebaseLocation(xDirEntry.parent_path().string());
		pxCodebaseUnit->m_sExtension = xDirEntry.extension();
		pxCodebaseUnit->m_nLevel = nLevel;
		pxCodebaseUnit->m_eType = bIsDirectory ? CodebaseUnit::eCBUDirectory : CodebaseUnit::eCBUFile;

		m_xCodebase.m_apxUnit.push_back(pxCodebaseUnit);
		} catch(const std::exception & ex) {
			std::cerr<<pxLooper->leaf() <<": " <<ex.what() <<std::endl;
		}
	}  //End of for()
}  

void Radar::dump()
{
	int i, n= m_xCodebase.m_apxUnit.size();
	std::string s;
	CodebaseUnit* pxCodebaseUnit = NULL;

	for(i=0; i< n; i++)
	{
		pxCodebaseUnit = m_xCodebase.m_apxUnit[i];

		cout << pxCodebaseUnit->m_sLocation << ",";
		cout << pxCodebaseUnit->m_sName << ",";
		cout << pxCodebaseUnit->m_eType;

		cout<<endl;
	}
}

void Radar::include(std::string sIncludeDir)
{
	bfs::path xInclude;
	xInclude = complete(path(sIncludeDir, native));
	m_axInclusions.push_back(xInclude);
}

void Radar::exclude(std::string sExcludeItem)
{
	m_asExclusions.push_back(sExcludeItem);
}

std::string	Radar::getAbsolutePath(std::string sFilename)
{
	size_t i=0, n=m_xCodebase.m_apxUnit.size();
	CodebaseUnit* pxItem;

	for(i=0;i<n;i++)
	{
		pxItem = m_xCodebase.m_apxUnit[i];
		if(pxItem->m_sName == sFilename)
		{
			sFilename = m_xCodebaseRoot.string();
			if(pxItem->m_sLocation!="")	sFilename += "/" + pxItem->m_sLocation;
			sFilename += "/" + pxItem->m_sName;

			return sFilename;
		}
	}

	return "";
}




